package cn.tedu.charging.order.service;

import cn.tedu.charging.common.constant.AmqpComponentConst;
import cn.tedu.charging.common.constant.MqttDestinationConst;
import cn.tedu.charging.common.pojo.message.ChargingStartCheckMessage;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.common.pojo.param.OrderAddParam;
import cn.tedu.charging.common.pojo.vo.VehicleVO;
import cn.tedu.charging.common.protocol.JsonResult;
import cn.tedu.charging.common.utils.CronUtil;
import cn.tedu.charging.common.utils.SnowflakeIdGenerator;
import cn.tedu.charging.order.amqp.AmqpProducer;
import cn.tedu.charging.order.feign.DeviceClient;
import cn.tedu.charging.order.feign.UserClient;
import cn.tedu.charging.order.mqtt.MqttProducer;
import cn.tedu.charging.order.utils.XxlJobTaskUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private DeviceClient deviceClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private MqttProducer<ChargingStartCheckMessage> mqttProducer;
    @Autowired
    private AmqpProducer<DelayCheckMessage> amqpProducer;


    private SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator();

    @Override
    public String createOrder(OrderAddParam param) {
        //1.利用枪id 调用device服务检查枪状态 订单要在 可用的状态下才能继续流程
        checkGun(param.getGunId());
        //2.利用车主id 调用user服务 检查车主状态 检查车辆信息是否完整
        checkUserAndVehicle(param.getUserId());
        //3.生成唯一标识,保证高并发环境下唯一 保证有序(为了海量生成的数据 存在有序的标识,可以高效查询)
        //订单编号生成 可以使用雪花算法
        String billId = idGenerator.nextId() + "";
        //4.给设备发送命令 自检设备 开启充电
        //4.1 主题名字 敞亮前缀+param.getPileId()
        String dest = MqttDestinationConst.START_GUN_CHECK_PREFIX + param.getPileId();
        //4.2 组织消息对象
        ChargingStartCheckMessage msg = new ChargingStartCheckMessage();
        msg.setGunId(param.getGunId());
        msg.setOrderNo(billId);
        msg.setUserId(param.getUserId());
        mqttProducer.send(dest, msg);
        //5.发送延迟消息 延迟检查自检结果
        DelayCheckMessage dlmsg = new DelayCheckMessage();
        dlmsg.setOrderNo(billId);
        dlmsg.setUserId(param.getUserId());
        amqpProducer.sendDelay(dlmsg, AmqpComponentConst.DELAY_BILL_EX);
        //6.生成计划任务,根据充电预估时长,兜底检查是否充电异常.
        //估算一个最大充电时间 （测试，设置为2分钟）
        String cron = CronUtil.delayCron(1000 * 2 * 60);
        XxlJobTaskUtil.createJobTask(new RestTemplate(), cron, 3, billId);
        return billId;
    }

    private void checkUserAndVehicle(Integer userId) {
        JsonResult<VehicleVO> result = userClient.bindVehicle(userId);
        if (result.getData() == null) {
            throw new RuntimeException("未绑定车辆");
        }
        if (result.getCode() != 0) {
            throw new RuntimeException("远程调用失败");
        }
    }

    private void checkGun(Integer gunId) {
        // 远程调用设备服务，检查反馈结果
        JsonResult<Boolean> result = deviceClient.checkGun(gunId);
        if (!result.getData()) {
            throw new RuntimeException("枪状态异常");
        }
        if (result.getCode() != 0) {
            throw new RuntimeException("远程调用失败");
        }
    }
}
